"""
主应用程序
会议视频文字自动记录系统
"""

import asyncio
import signal
import sys
import time
from typing import Optional
from contextlib import asynccontextmanager

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from .core import config, app_logger
from .api import router
from .video import VideoInputManager, StreamConfig, StreamType, FrameData
from .detection import YOLODetector, DetectionResult
from .processing import AsyncQueueManager, RegionCropper, CroppedRegion
from .ocr import PaddleOCRService, OCRBatchProcessor
from .postprocessing import TextPostProcessor
from .storage import DatabaseManager


class MeetingRecognitionApp:
    """会议识别应用主类"""
    
    def __init__(self):
        self.video_manager: Optional[VideoInputManager] = None
        self.yolo_detector: Optional[YOLODetector] = None
        self.queue_manager: Optional[AsyncQueueManager] = None
        self.region_cropper: Optional[RegionCropper] = None
        self.ocr_service: Optional[PaddleOCRService] = None
        self.ocr_processor: Optional[OCRBatchProcessor] = None
        self.text_processor: Optional[TextPostProcessor] = None
        self.db_manager: Optional[DatabaseManager] = None
        
        self.current_meeting_id: Optional[str] = None
        self.is_running = False
        
        app_logger.info("会议识别应用初始化")
    
    async def initialize(self):
        """初始化所有组件"""
        try:
            app_logger.info("开始初始化应用组件...")
            
            # 初始化数据库
            self.db_manager = DatabaseManager()
            app_logger.info("数据库管理器初始化完成")
            
            # 初始化YOLO检测器
            self.yolo_detector = YOLODetector()
            app_logger.info("YOLO检测器初始化完成")
            
            # 初始化区域裁剪器
            self.region_cropper = RegionCropper()
            app_logger.info("区域裁剪器初始化完成")
            
            # 初始化OCR服务
            self.ocr_service = PaddleOCRService()
            self.ocr_processor = OCRBatchProcessor(self.ocr_service)
            self.ocr_processor.start()
            app_logger.info("OCR服务初始化完成")
            
            # 初始化文本后处理器
            self.text_processor = TextPostProcessor()
            app_logger.info("文本后处理器初始化完成")
            
            # 初始化队列管理器
            self.queue_manager = AsyncQueueManager()
            self.queue_manager.start()
            app_logger.info("队列管理器初始化完成")
            
            # 初始化视频管理器
            self.video_manager = VideoInputManager()
            self.video_manager.add_frame_callback(self._on_frame_received)
            app_logger.info("视频管理器初始化完成")
            
            app_logger.info("所有组件初始化完成")
            
        except Exception as e:
            app_logger.error(f"应用初始化失败: {e}")
            raise
    
    async def cleanup(self):
        """清理资源"""
        app_logger.info("开始清理应用资源...")
        
        try:
            if self.video_manager:
                self.video_manager.cleanup()
            
            if self.queue_manager:
                self.queue_manager.stop()
            
            if self.ocr_processor:
                self.ocr_processor.stop()
            
            if self.ocr_service:
                self.ocr_service.cleanup()
            
            if self.db_manager:
                self.db_manager.cleanup()
            
            app_logger.info("应用资源清理完成")
            
        except Exception as e:
            app_logger.error(f"清理资源时出错: {e}")
    
    def start_meeting(self, meeting_id: str, title: Optional[str] = None) -> bool:
        """开始会议记录"""
        try:
            if self.current_meeting_id:
                app_logger.warning(f"已有活跃会议: {self.current_meeting_id}")
                return False
            
            # 创建会议记录
            success = self.db_manager.create_meeting(meeting_id, title)
            if not success:
                app_logger.error(f"创建会议记录失败: {meeting_id}")
                return False
            
            self.current_meeting_id = meeting_id
            self.is_running = True
            
            app_logger.info(f"开始会议记录: {meeting_id}")
            return True
            
        except Exception as e:
            app_logger.error(f"开始会议记录失败: {e}")
            return False
    
    def stop_meeting(self) -> bool:
        """停止会议记录"""
        try:
            if not self.current_meeting_id:
                app_logger.warning("没有活跃的会议")
                return False
            
            # 停止所有视频流
            if self.video_manager:
                self.video_manager.stop_all_streams()
            
            # 更新会议状态
            self.db_manager.update_meeting_status(self.current_meeting_id, "completed")
            
            app_logger.info(f"停止会议记录: {self.current_meeting_id}")
            
            self.current_meeting_id = None
            self.is_running = False
            
            return True
            
        except Exception as e:
            app_logger.error(f"停止会议记录失败: {e}")
            return False
    
    def add_video_stream(self, stream_config: StreamConfig) -> bool:
        """添加视频流"""
        if not self.video_manager:
            app_logger.error("视频管理器未初始化")
            return False
        
        return self.video_manager.add_stream(stream_config)
    
    def start_video_stream(self, stream_id: str) -> bool:
        """启动视频流"""
        if not self.video_manager:
            app_logger.error("视频管理器未初始化")
            return False
        
        return self.video_manager.start_stream(stream_id)
    
    def _on_frame_received(self, frame_data: FrameData):
        """帧接收回调"""
        if not self.is_running or not self.current_meeting_id:
            return
        
        try:
            # YOLO检测
            detection_result = self.yolo_detector.detect(frame_data.frame)
            
            if not detection_result.detections:
                return
            
            # 裁剪区域
            cropped_regions = self.region_cropper.crop_regions(frame_data, detection_result)
            
            if not cropped_regions:
                return
            
            # 提交OCR批处理任务
            self.ocr_processor.submit_batch(
                cropped_regions,
                callback=self._on_ocr_completed
            )
            
        except Exception as e:
            app_logger.error(f"帧处理失败: {e}")
    
    def _on_ocr_completed(self, batch_id: str, batch_result):
        """OCR完成回调"""
        try:
            if not self.current_meeting_id:
                return
            
            # 后处理
            processed_texts, segments = self.text_processor.process(batch_result.results)
            
            # 保存到数据库
            if processed_texts:
                self.db_manager.save_text_records(self.current_meeting_id, processed_texts)
            
            if segments:
                self.db_manager.save_segment_records(self.current_meeting_id, segments)
            
            app_logger.debug(
                f"OCR批处理完成: {batch_id}, "
                f"文本: {len(processed_texts)}, 段落: {len(segments)}"
            )
            
        except Exception as e:
            app_logger.error(f"OCR结果处理失败: {e}")


# 全局应用实例
app_instance = MeetingRecognitionApp()


@asynccontextmanager
async def lifespan(app: FastAPI):
    """应用生命周期管理"""
    # 启动
    await app_instance.initialize()
    yield
    # 关闭
    await app_instance.cleanup()


# 创建FastAPI应用
app = FastAPI(
    title="会议视频文字自动记录系统",
    description="基于YOLOv8和PaddleOCR的会议视频文字自动记录系统",
    version=config.system.version,
    lifespan=lifespan
)

# 添加CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=config.security.cors_origins,
    allow_credentials=True,
    allow_methods=config.security.cors_methods,
    allow_headers=config.security.cors_headers,
)

# 注册路由
app.include_router(router, prefix="/api/v1")


@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
    """全局异常处理器"""
    app_logger.error(f"未处理的异常: {exc}")
    return JSONResponse(
        status_code=500,
        content={
            "error": "Internal Server Error",
            "message": "服务器内部错误",
            "timestamp": time.time()
        }
    )


@app.get("/")
async def root():
    """根路径"""
    return {
        "name": config.system.name,
        "version": config.system.version,
        "status": "running",
        "api_docs": "/docs"
    }


def signal_handler(signum, frame):
    """信号处理器"""
    app_logger.info(f"接收到信号 {signum}，正在关闭应用...")
    sys.exit(0)


def main():
    """主函数"""
    import uvicorn
    
    # 注册信号处理器
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    
    app_logger.info(f"启动会议识别系统 v{config.system.version}")
    
    # 启动服务器
    uvicorn.run(
        "src.main:app",
        host=config.server.host,
        port=config.server.port,
        reload=config.server.reload,
        workers=config.server.workers,
        log_level=config.system.log_level.lower()
    )


if __name__ == "__main__":
    main()
